home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / Fields.C < prev    next >
C/C++ Source or Header  |  1992-08-24  |  18KB  |  846 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "Fields.h"
  6.  
  7. #include "Class.h"
  8. #include "Look.h"
  9. #include "GapText.h"
  10. #include "Manager.h"
  11. #include "RegularExp.h"
  12. #include "Clipper.h"
  13. #include "TextView.h"
  14. #include "Alert_e.h"
  15. #include "Window.h"
  16. #include "Math.h"
  17.  
  18. //---- TextViewOverlay ---------------------------------------------------------
  19.  
  20. static TextViewOverlay *gTVO;
  21.  
  22. ONEXIT(Fields)
  23. {
  24.     SafeDelete(gTVO);
  25. }
  26.  
  27. TextViewOverlay::TextViewOverlay()
  28. {
  29.     currentfield= 0;
  30.     ct= 0;
  31.     cl= 0;
  32.     tv= 0;
  33.     noupdate= FALSE;
  34. }
  35.  
  36. TextViewOverlay::~TextViewOverlay()
  37. {
  38.     currentfield= 0;
  39.     if (ct) {
  40.     Object *op;
  41.     Iter next(ct->GetObserverIter());
  42.     while (op= next())
  43.         ct->RemoveObserver(op);
  44.     SafeDelete(ct);
  45.     }
  46.     SafeDelete(cl);
  47.     SafeDelete(tv);
  48. }
  49.  
  50. bool TextViewOverlay::CopyInStr(EditField *ef, char *buf, int sz)
  51. {
  52.     if (ef == currentfield) {
  53.     ct->CopyInStr((byte*)buf, sz, 0, ct->Size());
  54.     return FALSE;
  55.     }
  56.     return TRUE;
  57. }
  58.  
  59. bool TextViewOverlay::Size(EditField *ef, int *sz)
  60. {
  61.     if (ef == currentfield) {
  62.     *sz= ct->End();
  63.     return FALSE;
  64.     }
  65.     return TRUE;
  66. }
  67.  
  68. bool TextViewOverlay::KbdFocus(EditField *ef, bool in, bool wordwrap)
  69. {
  70.     if (gDebug)
  71.     fprintf(stderr, "TextViewOverlay::KbdFocus(0x%08x, %d) old:0x%08x\n",
  72.                             ef, in, currentfield);
  73.     if (in) {
  74.     if (currentfield != 0) {
  75.         if (gDebug)
  76.         fprintf(stderr, "KbdFocus(in): oops\n");
  77.         return FALSE;
  78.     }
  79.     if (ef)
  80.         ef->Reveal();
  81.     char *es= ef->GetStringForEditing();
  82.     currentfield= ef;
  83.     currentfield->SetFlag(eEditFieldHasOverlay);
  84.  
  85.     if (ct == 0) {
  86.         ct= new GapText((byte*)es);
  87.         tv= new TextView(currentfield, gFitRect, ct, TRUE);
  88.         tv->SetDragAndDrop(FALSE);
  89.         tv->SetFlag(eViewNoPrint);
  90.         tv->SetStopChars("\r\n");
  91.         tv->ResetFlag(eVObjKbdFocus);
  92.         cl= new Clipper(tv);
  93.         cl->Open();
  94.     } else {
  95.         ct->ReplaceWithStr((byte*)es);
  96.         cl->RevealRect(Rectangle(0,0,1,1), gPoint1);
  97.     }
  98.     //ct->SetFont(currentfield->GetFont(), 0, ct->Size());
  99.     ct->SetFont(currentfield->GetFont());
  100.     if (gToken.Code != eEvtLeftButton)
  101.         tv->SelectAll(FALSE);
  102.  
  103.     ct->AddObserver(currentfield);
  104.     cl->SetContainer(currentfield);
  105.     tv->SetNextHandler(currentfield);
  106.     //cl->Open();
  107.  
  108.     if (wordwrap)
  109.         tv->SetWordWrap(TRUE);
  110.  
  111.     currentfield->SetExtent(currentfield->GetExtent());
  112.     currentfield->SetOrigin(currentfield->GetOrigin());
  113.     currentfield->ForceRedraw();
  114.     } else {
  115.     if (currentfield != ef) {
  116.         if (gDebug) {
  117.         fprintf(stderr, "KbdFocus(out): oops %d\n", currentfield);
  118.         }
  119.         return FALSE;
  120.     }
  121.     if (!Sync(currentfield))
  122.         return FALSE;
  123.     tv->SetWordWrap(FALSE);
  124.     currentfield->ForceRedraw();
  125.     cl->ClearContainer(currentfield);
  126.     ct->RemoveObserver(currentfield);
  127.     currentfield->ResetFlag(eEditFieldHasOverlay);
  128.     currentfield= 0;
  129.     }
  130.     return tv->KbdFocus(in);
  131. }
  132.  
  133. bool TextViewOverlay::Sync(EditField *ef)
  134. {
  135.     if (currentfield == ef) {
  136.     char *tmp= ct->AsString();
  137.     noupdate= TRUE;
  138.     bool valid= currentfield->ValidateString(tmp);
  139.     noupdate= FALSE;
  140.     delete tmp;
  141.     if (! valid) {
  142.         ct->ReplaceWithStr((byte*)currentfield->GetStringForEditing());
  143.         cl->RevealRect(Rectangle(0,0,1,1), gPoint1);
  144.         tv->SelectAll(FALSE);
  145.         return FALSE;
  146.     }
  147.     return TRUE;
  148.     }
  149.     return FALSE;
  150.  
  151. bool TextViewOverlay::Draw(EditField *ef, Rectangle r)
  152. {
  153.     if (currentfield == ef) {
  154.     cl->DrawAll(r);
  155.     return FALSE;
  156.     }
  157.     return TRUE;
  158. }
  159.  
  160. void TextViewOverlay::Update(EditField *ef)
  161. {
  162.     if (currentfield == ef && !noupdate) {
  163.     ct->ReplaceWithStr((byte*)currentfield->GetStringForEditing());
  164.     //if (ct->GetFont() != currentfield->GetFont())
  165.         ct->SetFont(currentfield->GetFont());
  166.     cl->RevealRect(Rectangle(0,0,1,1), gPoint1);
  167.     }
  168. }
  169.  
  170. void TextViewOverlay::SetOrigin(EditField *ef, Point at)
  171. {
  172.     if (currentfield == ef)
  173.     cl->SetOrigin(at);
  174. }
  175.  
  176. void TextViewOverlay::SetExtent(EditField *ef, Point e)
  177. {
  178.     if (currentfield == ef) {
  179.     cl->SetExtent(e);
  180.     if (tv->GetWordWrap())
  181.         tv->SetExtent(Point(e.x, cFit));
  182.     }
  183. }
  184.  
  185. Command *TextViewOverlay::DispatchEvents(EditField *ef, Point lp, Token &t, Clipper *vf)
  186. {
  187.     if (currentfield == ef)
  188.     return cl->Input(lp, t, vf);
  189.     return 0;
  190. }
  191.  
  192. void TextViewOverlay::DoSetupMenu(EditField *ef, Menu *m)
  193. {
  194.     if (currentfield == ef)
  195.     tv->DoSetupMenu(m);
  196. }
  197.  
  198. Command *TextViewOverlay::DoMenuCommand(EditField *ef, int c)
  199. {
  200.     if (currentfield == ef)
  201.     return tv->DoMenuCommand(c);
  202.     return gNoChanges;
  203. }
  204.  
  205. //---- Field ----------------------------------------------------------------
  206.  
  207. NewMetaImpl(Field,VObject, (TP(font), T(minwidth)));
  208.  
  209. Field::Field(int mw, Font *f)
  210. {
  211.     Init(mw, f);
  212. }
  213.  
  214. Field::Field(int id, int mw, Font *f) : VObject(id)
  215. {
  216.     Init(mw, f);
  217. }
  218.  
  219. void Field::Init(int mw, Font *f)
  220. {
  221.     font= f;
  222.     minwidth= mw;
  223.     SetFlag(eVObjVFixed);
  224. }
  225.  
  226. void Field::SetEditable(bool e)
  227. {
  228.     SetFlag(eVObjKbdFocus, e);
  229.     SetFlag(eEditFieldNoBorder, !e);
  230. }
  231.  
  232. char *Field::GetStringForDrawing()
  233. {
  234.     return AsString();
  235. }
  236.  
  237. void Field::SetFont(Font *fp)
  238. {
  239.     font= fp;
  240. }
  241.  
  242. Metric Field::GetMinSize()
  243. {
  244.     int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
  245.     return StaticTextView::MeasureText(GetStringForDrawing(), font, 
  246.                  minwidth, GetLines()).Expand(gBorder+Point(b));
  247. }
  248.  
  249. void Field::Draw(Rectangle)
  250. {
  251.     int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
  252.     Ink *ink= Enabled() ? gInkBlack : gLook->DisableInk();
  253.     StaticTextView::DrawBoxedText(contentRect.Inset(gBorder+Point(b)),
  254.                   GetStringForDrawing(), font, ink, GetLines() > 1);
  255. }
  256.  
  257. int Field::Compare(Object *op)
  258. {
  259.     char *t1= AsString(), *t2= Guard(op,Field)->AsString();
  260.     return StrCmp((byte*)t1, (byte*)t2, -1, sortmap);
  261. }
  262.  
  263. bool Field::IsEqual(Object *op)
  264. {
  265.     if (op == 0 || ! op->IsKindOf(Field))
  266.     return FALSE;
  267.     byte *s1= (byte*)AsString(), *s2= (byte*)op->AsString();
  268.     if (s1 == 0 || s2 == 0)
  269.     return FALSE;
  270.     return StrCmp(s1, s2, -1, sortmap) == 0;
  271. }
  272.  
  273. int Field::GetLines()
  274. {
  275.     return 1;
  276. }
  277.  
  278. OStream& Field::PrintOn (OStream &s)
  279. {
  280.     VObject::PrintOn(s);
  281.     return s << font SP << minwidth SP;
  282. }
  283.  
  284. IStream& Field::ReadFrom(IStream &s)
  285. {
  286.     VObject::ReadFrom(s);
  287.     return s >> font >> minwidth;
  288. }
  289.  
  290. //---- EditField ---------------------------------------------------------------
  291.  
  292. NewMetaImpl0(EditField,Field);
  293.  
  294. EditField::EditField(int id, int mw, Font *f) : Field(id, mw, f)
  295. {
  296.     SetFlag(eVObjEnabled | eVObjKbdFocus);
  297. }
  298.  
  299. EditField::~EditField()
  300. {
  301.     //if (HasOverlay())
  302.     //    GetTextViewOverlay()->KbdFocus(this, FALSE, FALSE);
  303. }
  304.  
  305. TextViewOverlay *EditField::GetTextViewOverlay()
  306. {
  307.     Manager *m= (Manager*) FindNextHandlerOfClass(Meta(Manager));
  308.     if (m)
  309.     return m->GetTextViewOverlay();
  310.  
  311.     if (gDebug) {
  312.     fprintf(stderr, "EditField::GetTextViewOverlay\n");
  313.     if (GetNextHandler())
  314.         fprintf(stderr, "GetNextHandler(): %s\n", GetNextHandler()->ClassName());
  315.     else
  316.         fprintf(stderr, "GetNextHandler(): 0\n");
  317.     }
  318.  
  319.     if (gTVO == 0)
  320.     gTVO= new TextViewOverlay;
  321.     return gTVO;
  322. }
  323.  
  324. char *EditField::GetStringForEditing()
  325. {
  326.     return AsString();
  327. }
  328.  
  329. void EditField::Draw(Rectangle r)
  330. {
  331.     if (!HasOverlay() || GetTextViewOverlay()->Draw(this, r))
  332.     Field::Draw(r);
  333.     gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->Adorn(this, r, HasOverlay());
  334. }
  335.  
  336. void EditField::Update(bool redraw)
  337. {
  338.     if (HasOverlay())
  339.     GetTextViewOverlay()->Update(this);
  340.     if (redraw)
  341.     InvalidateRect(contentRect.Inset(gPoint4));
  342.     //ForceRedraw();
  343. }
  344.  
  345. void EditField::Sync()
  346. {
  347.     if (HasOverlay())
  348.     GetTextViewOverlay()->Sync(this);
  349. }
  350.  
  351. static bool lock;
  352.  
  353. void EditField::DoSetupMenu(Menu *m)
  354. {
  355.     if (HasOverlay() && !lock) {
  356.     lock= TRUE;
  357.     GetTextViewOverlay()->DoSetupMenu(this, m);
  358.     lock= FALSE;
  359.     } else
  360.     Field::DoSetupMenu(m);
  361. }
  362.  
  363. Command *EditField::DoMenuCommand(int c)
  364. {
  365.     if (HasOverlay() && !lock) {
  366.     lock= TRUE;
  367.     Command *cmd= GetTextViewOverlay()->DoMenuCommand(this, c);
  368.     lock= FALSE;
  369.     return cmd;
  370.     }
  371.     return Field::DoMenuCommand(c);
  372. }
  373.  
  374. Command *EditField::Input(Point lp, Token &t, Clipper *vf)
  375. {
  376.     if (t.IsKey()) {
  377.     if (t.Code == '\t') {
  378.         Manager *m= (Manager*) FindNextHandlerOfClass(Meta(Manager));
  379.         if (m)
  380.         m->TabFields(t);
  381.         return gNoChanges;
  382.     }
  383.     if ((t.Code == '\r' || t.Code == '\n') && GetLines() <= 1) {
  384.         Manager *m= (Manager*) FindNextHandlerOfClass(Meta(Manager));
  385.         if (m)
  386.         m->TabFields(t);
  387.         return gNoChanges;
  388.     }
  389.     }
  390.     return Field::Input(lp, t, vf);
  391. }
  392.  
  393. void EditField::SetOrigin(Point at)
  394. {
  395.     Field::SetOrigin(at);
  396.     if (HasOverlay()) {
  397.     int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
  398.     GetTextViewOverlay()->SetOrigin(this, at+Point(b));
  399.     }
  400. }
  401.  
  402. void EditField::SetExtent(Point e)
  403. {
  404.     Field::SetExtent(e);
  405.     if (HasOverlay()) {
  406.     int b= (int)gLook->FieldBorderLayout(TestFlag(eEditFieldNoBorder))->GetValue(this, 0);
  407.     GetTextViewOverlay()->SetExtent(this, e-2*Point(b));
  408.     }
  409. }
  410.  
  411. bool EditField::KbdFocus(bool in)
  412. {
  413.     if (HasOverlay() != in)
  414.         return GetTextViewOverlay()->KbdFocus(this, in, GetLines() > 1);
  415.     return TRUE;
  416. }
  417.  
  418. void EditField::Control(int id, int part, void *val)
  419. {
  420.     switch (part) {
  421.     case cPartSelectionChanged:
  422.     case cPartViewSize:
  423.     case cPartOriginChanged:
  424.     case cPartExtentChanged:
  425.     case cPartScrollPos:
  426.     break;
  427.  
  428.     case cPartChangedText:
  429.     Field::Control(GetId(), part, val);
  430.     break;
  431.  
  432.     default:
  433.     if (gDebug)
  434.         fprintf(stderr, "EditField::Control(%d, %d, %d)\n", id, part, val);
  435.     Field::Control(id, part, val);
  436.     break;
  437.     }
  438. }
  439.  
  440. Command *EditField::DispatchEvents(Point lp, Token &t, Clipper *vf)
  441. {
  442.     Command *cmd;
  443.     if (HasOverlay() && (cmd= GetTextViewOverlay()->DispatchEvents(this, lp, t, vf)))
  444.     return cmd;
  445.     return Field::DispatchEvents(lp, t, vf);
  446. }
  447.  
  448. bool EditField::ValidateString(char*)
  449. {
  450.     // called when content in TextView needs to be checked, eg. focus loss
  451.     // override for validation, reformatting and completion of string
  452.     // return FALSE if not acceptable
  453.     return TRUE;
  454. }
  455.  
  456. void EditField::Open(bool mode)
  457. {
  458.     Field::Open(mode);
  459. }
  460.  
  461. //---- TextField ---------------------------------------------------------------
  462.  
  463. NewMetaImpl(TextField,EditField, (TP(text)));
  464.  
  465. TextField::TextField(int id, int minWidthInChars, Font *f) : EditField(id, 0, f)
  466. {
  467.     text= 0;
  468.     strreplace(&text, "");
  469.     minwidth= font->Width('w') * minWidthInChars;
  470. }
  471.  
  472. TextField::TextField(int id, int minWidthInPixel, char *t) : EditField(id, minWidthInPixel)
  473. {
  474.     text= 0;
  475.     if (t == 0)
  476.     t= "";
  477.     strreplace(&text, t);
  478. }
  479.  
  480. TextField::~TextField()
  481. {
  482.     SafeDelete(text);
  483. }
  484.  
  485. char *TextField::AsString()
  486. {
  487.     return text;
  488. }
  489.  
  490. void TextField::SetString(char *t, bool redraw)
  491. {
  492.     strreplace(&text, t);
  493.     Update(redraw);
  494.     Changed();
  495. }
  496.  
  497. void TextField::SetFString(bool redraw, char *va_(fmt), ...)
  498. {
  499.     va_list ap;
  500.     va_start(ap,va_(fmt));
  501.     strfreplace(&text, va_(fmt), ap);
  502.     Update(redraw);
  503.     Changed();
  504.     va_end(ap);
  505. }
  506.  
  507. void TextField::GetString(char *buf, int sz)
  508. {
  509.     if (!HasOverlay() || GetTextViewOverlay()->CopyInStr(this, buf, sz)) {
  510.     if (text)
  511.         strn0cpy(buf, text, sz);
  512.     else
  513.         strcpy(buf, "");
  514.     }
  515. }
  516.  
  517. char *TextField::GetString()
  518. {
  519.     Sync();
  520.     return AsString();
  521. }
  522.  
  523. int TextField::GetTextSize()
  524. {
  525.     int sz= 0;
  526.     if (!HasOverlay() || GetTextViewOverlay()->Size(this, &sz))
  527.     if (text)
  528.         sz= strlen(text);
  529.     return sz;
  530. }
  531.  
  532. OStream& TextField::PrintOn (OStream &s)
  533. {
  534.     EditField::PrintOn(s);
  535.     return s.PrintString(text);
  536. }
  537.  
  538. IStream& TextField::ReadFrom(IStream &s)
  539. {
  540.     char *t;
  541.     EditField::ReadFrom(s);
  542.     s.ReadString(&t);
  543.     SetString(t, FALSE);
  544.     return s;
  545. }
  546.  
  547. bool TextField::ValidateString(char *s)
  548. {
  549.     SetString(s, FALSE);
  550.     return TRUE;
  551. }
  552.  
  553. //---- MultiLineField ----------------------------------------------------------
  554.  
  555. NewMetaImpl(MultiLineField,TextField, (T(lines)));
  556.  
  557. MultiLineField::MultiLineField(int id, int l, int mw, char *t)
  558.                             : TextField(id, mw, t)
  559. {
  560.     lines= Math::Max(0, l);
  561. }
  562.     
  563. int MultiLineField::GetLines()
  564. {
  565.     return lines;
  566. }
  567.  
  568. OStream& MultiLineField::PrintOn (OStream &s)
  569. {
  570.     TextField::PrintOn(s);
  571.     return s << lines SP;
  572. }
  573.  
  574. IStream& MultiLineField::ReadFrom(IStream &s)
  575. {
  576.     TextField::ReadFrom(s);
  577.     return s >> lines;
  578. }
  579.  
  580. //---- FormatField -------------------------------------------------------------
  581.  
  582. NewMetaImpl(FormatField,EditField, (TP(format)));
  583.  
  584. FormatField::FormatField(int id, char *fmt) : EditField(id)
  585. {
  586.     format= strsave(fmt);
  587. }
  588.  
  589. FormatField::~FormatField()
  590. {
  591.     SafeDelete(format);
  592. }
  593.  
  594. OStream& FormatField::PrintOn(OStream &s)
  595. {
  596.     EditField::PrintOn(s);
  597.     return s.PrintString(format);
  598. }
  599.  
  600. IStream& FormatField::ReadFrom(IStream &s)
  601. {
  602.     EditField::ReadFrom(s);
  603.     SafeDelete(format);
  604.     return s.ReadString(&format);
  605. }
  606.  
  607. //---- IntField ----------------------------------------------------------------
  608.  
  609. NewMetaImpl(IntField,FormatField, (T(value), T(minVal), T(maxVal)));
  610.  
  611. IntField::IntField(int id, int mi, int ma, char *fmt) : FormatField(id, fmt)
  612. {
  613.     Init(0, mi, ma);
  614. }
  615.  
  616. IntField::IntField(int id, int val, int mi, int ma, char *fmt) : FormatField(id, fmt)
  617. {
  618.     Init(val, mi, ma);
  619. }
  620.  
  621. void IntField::Init(int val, int mi, int ma)
  622. {
  623.     minVal= mi;
  624.     maxVal= ma;
  625.     int lmin= font->Width((byte*)form(format, minVal));
  626.     int lmax= font->Width((byte*)form(format, maxVal));
  627.     minwidth= Math::Max(lmin, lmax);
  628.     SetValue(val, FALSE);
  629. }
  630.  
  631. char *IntField::AsString()
  632. {
  633.     return form(format, value);
  634. }
  635.  
  636. char *IntField::GetStringForDrawing()
  637. {
  638.     return form(format, value);
  639. }
  640.  
  641. int IntField::GetValue()
  642. {
  643.     Sync();
  644.     return value;
  645. }
  646.  
  647. bool IntField::SetValue(int newVal, bool redraw)
  648. {
  649.     newVal= Math::Range(minVal, maxVal, newVal);
  650.     if (newVal != value) {
  651.     value= newVal;
  652.     Update(redraw);
  653.     return TRUE;
  654.     }
  655.     return FALSE;
  656. }
  657.  
  658. void IntField::GetRange(int &mi, int &ma)
  659. {
  660.     mi= minVal;
  661.     ma= maxVal;
  662. }
  663.  
  664. void IntField::SetRange(int mi, int ma)
  665. {
  666.     minVal= mi;
  667.     maxVal= ma;
  668.     SetValue(value);
  669. }
  670.  
  671. OStream& IntField::PrintOn(OStream &s)
  672. {
  673.     FormatField::PrintOn(s);
  674.     return s << value SP << minVal SP << maxVal SP;
  675. }
  676.  
  677. IStream& IntField::ReadFrom(IStream &s)
  678. {
  679.     int newval;
  680.     FormatField::ReadFrom(s);
  681.     s >> newval >> minVal >> maxVal;
  682.     SetValue(newval, FALSE);
  683.     return s;
  684. }
  685.  
  686. bool IntField::ValidateString(char *s)
  687. {
  688.     int newval;
  689.     if (sscanf(s, "%d", &newval) != 1) {
  690.     ShowAlert(eAlertNote, "\"%s\" is not a number", s);
  691.     return FALSE;
  692.     }
  693.     
  694.     if (newval < minVal || newval > maxVal) {
  695.     ShowAlert(eAlertNote, "%d not in range %d-%d", newval, minVal, maxVal);
  696.     return FALSE;
  697.     }
  698.     if (SetValue(newval))
  699.     Control(GetId(), cPartValueChanged, &newval);
  700.     return TRUE;
  701. }
  702.  
  703. //---- FloatField ----------------------------------------------------------------
  704.  
  705. NewMetaImpl(FloatField,FormatField, (T(value), T(minVal), T(maxVal)));
  706.  
  707. FloatField::FloatField(int id, double mi, double ma, char *fmt) : FormatField(id, fmt)
  708. {
  709.     Init(0.0, mi, ma);
  710. }
  711.  
  712. FloatField::FloatField(int id, double val, double mi, double ma, char *fmt)
  713.                             : FormatField(id, fmt)
  714. {
  715.     Init(val, mi, ma);
  716. }
  717.  
  718. void FloatField::Init(double val, double mi, double ma)
  719. {
  720.     minVal= mi;
  721.     maxVal= ma;
  722.     int lmin= font->Width((byte*)form(format, minVal));
  723.     int lmax= font->Width((byte*)form(format, maxVal));
  724.     minwidth= Math::Max(lmin, lmax);
  725.     SetValue(val, FALSE);
  726. }
  727.  
  728. char *FloatField::AsString()
  729. {
  730.     return form(format, value);
  731. }
  732.  
  733. char *FloatField::GetStringForDrawing()
  734. {
  735.     return form(format, value);
  736. }
  737.  
  738. double FloatField::GetValue()
  739. {
  740.     Sync();
  741.     return value;
  742. }
  743.  
  744. bool FloatField::SetValue(double newVal, bool redraw)
  745. {
  746.     newVal= Math::Range(minVal, maxVal, newVal);
  747.     if (newVal != value) {
  748.     value= newVal;
  749.     Update(redraw);
  750.     return TRUE;
  751.     }
  752.     return FALSE;
  753. }
  754.  
  755. void FloatField::GetRange(double &mi, double &ma)
  756. {
  757.     mi= minVal;
  758.     ma= maxVal;
  759. }
  760.  
  761. void FloatField::SetRange(double mi, double ma)
  762. {
  763.     minVal= mi;
  764.     maxVal= ma;
  765.     SetValue(value);
  766. }
  767.  
  768. OStream& FloatField::PrintOn(OStream &s)
  769. {
  770.     FormatField::PrintOn(s);
  771.     return s << value SP << minVal SP << maxVal SP;
  772. }
  773.  
  774. IStream& FloatField::ReadFrom(IStream &s)
  775. {
  776.     double newval;
  777.     FormatField::ReadFrom(s);
  778.     s >> newval >> minVal >> maxVal;
  779.     SetValue(newval, FALSE);
  780.     return s;
  781. }
  782.  
  783. bool FloatField::ValidateString(char *s)
  784. {
  785.     double newval;
  786.     if (sscanf(s, "%lf", &newval) != 1) {
  787.     ShowAlert(eAlertNote, "\"%s\" is not a number", s);
  788.     return FALSE;
  789.     }
  790.     
  791.     if (newval < minVal || newval > maxVal) {
  792.     ShowAlert(eAlertNote, "%g not in range %g-%g", newval, minVal, maxVal);
  793.     return FALSE;
  794.     }
  795.     if (SetValue(newval))
  796.     Control(GetId(), cPartValueChanged, &newval);
  797.     return TRUE;
  798. }
  799.  
  800. //---- RegExpField ----------------------------------------------------------
  801.  
  802. NewMetaImpl(RegExpField,TextField, (TP(regex), TP(errmsg)));
  803.  
  804. RegExpField::RegExpField(int id, RegularExp *r, int mw, char *msg, char *t)
  805.                             : TextField(id, mw, t)
  806. {
  807.     regex= r;
  808.     if (msg == 0)
  809.     msg= "Illegal format \"%s\" ";
  810.     errmsg= 0;
  811.     strreplace(&errmsg, msg);
  812. }
  813.  
  814. RegExpField::~RegExpField()
  815. {
  816.     SafeDelete(regex);
  817.     SafeDelete(errmsg);
  818. }
  819.  
  820. bool RegExpField::ValidateString(char *s)
  821. {
  822.     TextField::ValidateString(s);
  823.     if (strlen(s) && regex->Match(s) != strlen(s)) {
  824.     ShowAlert(eAlertNote, errmsg, s);
  825.     return FALSE;
  826.     }
  827.     return TRUE;
  828. }
  829.  
  830. OStream& RegExpField::PrintOn(OStream &s)
  831. {
  832.     TextField::PrintOn(s);
  833.     s << regex SP;
  834.     return s.PrintString(errmsg);
  835. }
  836.  
  837. IStream& RegExpField::ReadFrom(IStream &s)
  838. {
  839.     TextField::ReadFrom(s);
  840.     s >> regex;
  841.     SafeDelete(errmsg);
  842.     return s.ReadString(&errmsg);
  843. }
  844.  
  845.